package com.fengchao.util.wechat.commonality;

import com.fengchao.api.config.WeChatConfig;
import com.fengchao.model.entity.comm.Message;
import com.fengchao.util.common.RandomUtil;
import com.fengchao.util.net.HttpUtil;
import com.fengchao.util.wechat.commonality.rendermodel.Menu;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信公众平台应用开发的基本配置
 *
 * @author xuri002
 */
public class WeChatUtil {

    private static final Logger logger = LoggerFactory.getLogger(WeChatUtil.class);
    //保存向微信发送请求时需要的Token
    //里面存储三个值 ，用户可以使用getAvailableAccessToken()方法获取有效的token值
    //key：access_token value ：token值
    //key：expires_in value ：有效时间，单位：秒
    //key：updateTime value ：token的更新时间
    private static Map<String, Object> accessToken = new HashMap<String, Object>();
    private static Map<String, Object> jsapiTicket = new HashMap<String, Object>();
    public static Gson gson = new GsonBuilder().disableHtmlEscaping().create(); //不转义html

    /**
     * 验证签名
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] arr = new String[]{"", timestamp, nonce};
        // 将token、timestamp、nonce三个参数进行字典序排序
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        content = null;
        // 将sha1加密后的字符串可与signature对比，标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }


    /**
     * 获取有效的accessToken
     *
     * @return
     */
    public static String getAvailableAccessToken() {
        if (accessToken.isEmpty()) {//第一次获得token
            updateAccessToken();
        } else {
            int int_expires_in = (Integer) accessToken.get("expires_in");
            DateTime updateTime = (DateTime) accessToken.get("updateTime");
            if (updateTime.plusSeconds(int_expires_in - 600).isBeforeNow()) {//过期时间前1200秒重新刷新
                updateAccessToken();
            }
        }
        String access_token = (String) accessToken.get("access_token");//获取token
        return access_token;
    }

    /**
     * 更新accessToken
     */
    private synchronized static void updateAccessToken() {
        String access_token_json = HttpUtil.get(WeChatConfig.WECHAT_URL_ACCESSTOKEN + "?grant_type=client_credential&" + "appid=" + WeChatConfig.APPID + "&secret=" + WeChatConfig.APP_SECRET);
        if (!access_token_json.contains("errcode")) {
            accessToken.clear();
            DateTime now = new DateTime();
            JsonObject jsonObject = gson.fromJson(access_token_json, JsonObject.class);
            accessToken.put("access_token", jsonObject.get("access_token").getAsString());
            accessToken.put("expires_in", jsonObject.get("expires_in").getAsInt());
            accessToken.put("updateTime", now);
        }
    }


    /**
     * 获取有效的jsapi_ticket
     *
     * @return
     */
    public static String getAvailableJsapiTicket() {
        if (jsapiTicket.isEmpty()) {//第一次获得token
            updateJsapiTicket();
        } else {
            int int_expires_in = (Integer) jsapiTicket.get("expires_in");
            DateTime updateTime = (DateTime) jsapiTicket.get("updateTime");
            if (updateTime.plusSeconds(int_expires_in - 600).isBeforeNow()) {//过期时间前1200秒重新刷新
                updateJsapiTicket();
            }
        }
        String ticket = (String) jsapiTicket.get("ticket");//获取Ticket
        return ticket;
    }


    /**
     * 更新jsapi_ticket
     */
    private synchronized static void updateJsapiTicket() {
        String jsapi_ticket_json = HttpUtil.get(WeChatConfig.WECHAT_URL_JSAPI_TICKET + "?access_token=" + getAvailableAccessToken() + "&type=jsapi");
        JsonObject jsonObject = gson.fromJson(jsapi_ticket_json, JsonObject.class);
        if ("0".equalsIgnoreCase(jsonObject.get("errcode").toString())) {
            jsapiTicket.clear();
            DateTime now = new DateTime();
            jsapiTicket.put("ticket", jsonObject.get("ticket").getAsString());
            jsapiTicket.put("expires_in", jsonObject.get("expires_in").getAsInt());
            jsapiTicket.put("updateTime", now);
        }
    }

    /**
     * jsapi签名
     *
     * @param jsapi_ticket
     * @param url
     * @return
     */
    public static Map<String, String> JsapiSign(String jsapi_ticket, String url) {
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = RandomUtil.getUUID();
        String timestamp = RandomUtil.create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写，且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;


        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToStr(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);

        return ret;
    }


    /**
     * 生成自定义的菜单
     * json格式的菜单
     *
     * @param
     */

    public static Message creatMenu(Menu menu) {
        Message message = new Message();
        String resultJson = HttpUtil.post(WeChatConfig.WECHAT_URL_CREATMENU + "?access_token=" + getAvailableAccessToken(), gson.toJson(menu));
        JsonObject jsonObject = gson.fromJson(resultJson, JsonObject.class);
        if (WeChatConfig.SUCCESS == jsonObject.get("errcode").getAsInt()) {
            message.setSuccess(true);
        } else {
            message.setSuccess(false);
            message.setMessage(jsonObject.get("errmsg").toString());
        }
        return message;
    }

    public static Message creatMenu(String json) {
        Message message = new Message();
        String resultJson = HttpUtil.post(WeChatConfig.WECHAT_URL_CREATMENU + "?access_token=" + getAvailableAccessToken(), json);
        JsonObject jsonObject = gson.fromJson(resultJson, JsonObject.class);
        if (WeChatConfig.SUCCESS == jsonObject.get("errcode").getAsInt()) {
            message.setSuccess(true);
        } else {
            message.setSuccess(false);
            message.setMessage(jsonObject.get("errmsg").toString());
        }
        return message;
    }

    /**
     * 获取自定义的菜单
     *
     * @param
     */
    public static String getMenu() {
        String resultJson = HttpUtil.get(WeChatConfig.WECHAT_URL_GETMENU + "?access_token=" + getAvailableAccessToken());
        return resultJson;
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }


    /**
     * 将字节转换为十六进制字符串
     *
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }
}
